/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年9月9日
 */
package com.massyframework.beanskin.license.signature.wizard;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.util.IOUtils;
import com.massyframework.beanskin.util.version.VersionRange;

/**
 * @author huangkh
 *
 */
public class ModuleParser {
		
	private static String MODULE = "MODULE/";
	private static List<String> XMLNAMES = 
			Arrays.asList(
					"/library.xml", 
					"/plugin.xml", 
					"/assembly.xml", 
					"/fragment.xml");
	
	private static final String X509CERT     = "x509cert";
	private static final String SECURE       = "secure";
	
	private static final String GROUPID      = "groupId";
	private static final String MODULEID     = "moduleId";
	private static final String VERSION      = "version";
	private static final String NAME         = "name";
	
	/**
	 * 
	 */
	public ModuleParser() {
		
	}
	
	public List<Module> parseJarFile(File jarFile) {
		List<Module> result = new ArrayList<>();
		try {
			JarFile jar = new JarFile(jarFile);
			
			List<JarEntry> entries = this.foundModuleXmls(jar);
			for (JarEntry entry: entries) {
				InputStream is = null;
				try {
					is = jar.getInputStream(entry);
					
					Module module = this.parseModuleIdentifier(is);
					result.add(module);
				}catch(Exception e) {
					e.printStackTrace();
				}finally {
					IOUtils.close(is);
				}
			}
		}catch(Exception e) {
		}
		
		return result;
	}
	
	/**
	 * 解析配置文件的模块标识符
	 * @param is {@link InputStream},输入流
	 * @return {@link ModuleIdentifier}
	 * @throws SAXException
	 * @throws IOException
	 * @throws ParserConfigurationException
	 */
	protected Module parseModuleIdentifier(InputStream is) 
			throws SAXException, IOException, ParserConfigurationException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse(is);
		
		NodeList nodes = doc.getDocumentElement().getChildNodes();
		int size = nodes.getLength();
		
		Module module = new Module();
		for (int i=0; i<size; i++) {
			Node node = nodes.item(i);
			String name = node.getNodeName();
			if (name.equals(GROUPID)) {
				module.setGroupId(this.getTextContent(node));
				continue;
			}
			if (name.equals(MODULEID)) {
				module.setModuleId(this.getTextContent(node));
				continue;
			}
			if (name.equals(VERSION)) {
				module.setVersionRange(VersionRange.valueOf(this.getTextContent(node)));
				continue;
			}
			
			if (name.equals(NAME)) {
				module.setName(this.getTextContent(node));
				continue;
			}
			
			if (name.equals(SECURE    )) {
				String certName = this.doParseX509Cert(node.getChildNodes());
				if (certName != null) {
					module.setCertAlias(certName);
				}
				continue;
			}
		}
		
		//如果无证书名称，代表没有许可要求，则无需签发许可。
		return module.getCertAlias() == null ? null : module;
	}
	
	protected String doParseX509Cert(NodeList nodes) {
		int size = nodes.getLength();
		for (int i=0; i<size; i++) {
			Node node = nodes.item(i);
			String name = node.getNodeName();
			if (name.equals(X509CERT)) {
				return this.doParseX509CertName(node.getChildNodes());
			}
		}
		
		return null;
	}
	
	protected String doParseX509CertName(NodeList nodes) {
		int size = nodes.getLength();
		for (int i=0; i<size; i++) {
			Node node = nodes.item(i);
			String name = node.getNodeName();
			if (name.equals(NAME)) {
				return this.getTextContent(node);
			}
		}
		
		return null;
	}
	
	/**
     * 获取节点的TextContent数据
     * @param node 节点
     * @return {@link String}, 可以返回null.
     */
    private String getTextContent(Node node){
        if (node == null) return null;

        String result = node.getTextContent();
        if (result == null){
            return null;
        }

        result = result.trim();
        if (result.isEmpty()){
            return null;
        }

        return result;
    }

	
	/**
	 * 发现模块xml配置文件
	 * @param jarFile {@link JarFile}
	 * @return {@link List}
	 * @throws IOException
	 */
	protected List<JarEntry> foundModuleXmls(JarFile jarFile) throws IOException {
		List<JarEntry> entries = new ArrayList<JarEntry>();
		
		Enumeration<JarEntry> em = jarFile.entries();
		while (em.hasMoreElements()) {
			JarEntry entry = em.nextElement();
			if (entry.isDirectory()) {
				continue;
			}
			
			String name = entry.getName();
			if (name.startsWith(MODULE) && name.endsWith(".xml")) {
				for (String xml: XMLNAMES) {
					if (name.endsWith(xml)) {
						entries.add(entry);
					}
				}
			}
		}
		
		if (entries.isEmpty()) {
			return Collections.emptyList();
		}
		
		List<JarEntry> result = new ArrayList<>();
		
		for (JarEntry entry: entries) {
			String[] arr = entry.getName().split("/");
			if (arr.length == 5) {
				result.add(entry);
			}
		}
		
		return result;
	}
}
